package com.material.pound.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.material.common.exception.ServiceException;
import com.material.common.utils.Arith;
import com.material.common.utils.DateUtils;
import com.material.common.utils.JsonUtils;
import com.material.common.utils.StringUtils;
import com.material.common.utils.bean.BeanUtil;
import com.material.event.entity.PoundSettleBatchEvent;
import com.material.event.entity.PoundSettleEvent;
import com.material.factory.consts.FuelAttributeRule;
import com.material.factory.domain.FactoryFuel;
import com.material.factory.domain.FactoryFuelAttribute;
import com.material.factory.domain.FactoryFuelRule;
import com.material.factory.mapper.FactoryFuelAttributeMapper;
import com.material.factory.mapper.FactoryFuelMapper;
import com.material.factory.vo.FactoryFuelRuleSaveVo;
import com.material.pound.FuelPoundParams;
import com.material.pound.consts.PoundState;
import com.material.pound.domain.FuelPound;
import com.material.pound.domain.FuelPoundAssay;
import com.material.pound.domain.FuelPoundIncentive;
import com.material.pound.mapper.FuelPoundAssayMapper;
import com.material.pound.mapper.FuelPoundIncentiveMapper;
import com.material.pound.mapper.FuelPoundMapper;
import com.material.pound.params.FuelPoundImportExtendParams;
import com.material.pound.params.FuelPoundImportParams;
import com.material.pound.params.FuelPoundQuery;
import com.material.pound.params.FuelPoundQueryParams;
import com.material.pound.params.FuelPoundSettleParams;
import com.material.pound.params.FuelPoundUpdate;
import com.material.pound.service.IFuelPoundService;
import com.material.pound.vo.FuelAssayResultVo;
import com.material.pound.vo.FuelAttributeVo;
import com.material.pound.vo.FuelDiaryVo;
import com.material.pound.vo.FuelPoundDetailVo;
import com.material.pound.vo.FuelPoundListVo;
import com.material.pound.vo.FuelPoundSettleVo;
import com.material.supplier.domain.SupplierInfo;
import com.material.supplier.mapper.SupplierInfoMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 磅单信息Service业务层处理
 *
 * @author ruoyi
 * @date 2025-05-07
 */
@Service
public class FuelPoundServiceImpl implements IFuelPoundService
{
    private static Logger logger = LoggerFactory.getLogger(FuelPoundServiceImpl.class);

    @Autowired
    private FuelPoundMapper fuelPoundMapper;
    @Autowired
    private FuelPoundAssayMapper fuelPoundAssayMapper;
    @Autowired
    private FuelPoundIncentiveMapper fuelPoundIncentiveMapper;
    @Autowired
    private FactoryFuelAttributeMapper factoryFuelAttributeMapper;
    @Autowired
    private FactoryFuelMapper factoryFuelMapper;
    @Autowired
    private SupplierInfoMapper supplierInfoMapper;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 查询磅单信息
     *
     * @param id 磅单信息主键
     * @return 磅单信息
     */
    @Override
    public FuelPound selectFuelPoundById(Long id)
    {
        return fuelPoundMapper.selectFuelPoundById(id);
    }

    @Override
    public FuelPoundDetailVo selectFuelById(Long id) {
        FuelPound fuelPound = fuelPoundMapper.selectFuelPoundById(id);
        FuelPoundDetailVo fuelPoundDetailVo = BeanUtil.copyProperties(fuelPound, FuelPoundDetailVo.class);
        FactoryFuelAttribute query = new FactoryFuelAttribute();
        query.setFuelId(fuelPound.getFuelId());
        List<FactoryFuelAttribute> factoryFuelAttributes = factoryFuelAttributeMapper.selectFactoryFuelAttributeList(query);
        List<FuelAttributeVo> fuelAttributeVos = BeanUtil.copyProperties(factoryFuelAttributes, FuelAttributeVo.class);
        fuelPoundDetailVo.setAttributeList(fuelAttributeVos);
        return fuelPoundDetailVo;
    }

    /**
     * 查询磅单信息列表
     *
     * @param fuelPound 磅单信息
     * @return 磅单信息
     */
    @Override
    public List<FuelPound> selectFuelPoundList(FuelPound fuelPound)
    {
        return fuelPoundMapper.selectFuelPoundList(fuelPound);
    }

    @Override
    public List<FuelPound> selectFuelPoundSettleList(FuelPoundQuery fuelPound) {
        return fuelPoundMapper.selectFuelPoundSettleList(fuelPound);
    }

    @Override
    public List<FuelPoundListVo> selectFuelPoundPageList(FuelPoundQueryParams fuelPound) {
        List<FuelPound> fuelPounds = fuelPoundMapper.selectFuelPoundPageList(fuelPound);
        if(CollectionUtils.isEmpty(fuelPounds)){
            return new ArrayList<>();
        }
        List<FuelPoundListVo> fuelPoundDetailVos = BeanUtil.copyProperties(fuelPounds, FuelPoundListVo.class);
        fuelPoundDetailVos.forEach(f->{
            String assayResult = f.getAssayResult();
            if(StringUtils.isBlank(assayResult)){
                return;
            }
            List<FuelAssayResultVo> attributeVos = JsonUtils.array2List(assayResult, FuelAssayResultVo.class);
            f.setAssayResultList(attributeVos);
        });

//        Set<Long> fuelIds = fuelPoundDetailVos.stream().map(FuelPoundDetailVo::getFuelId).collect(Collectors.toSet());
//        List<FactoryFuelAttribute> factoryFuelAttributes = factoryFuelAttributeMapper.selectFactoryFuelAttributeByFuelIds(fuelIds);
//        Map<Long, List<FuelAttributeVo>> attributesMap = new HashMap<>();
//        if(CollectionUtils.isNotEmpty(factoryFuelAttributes)){
//            List<FuelAttributeVo> attributes = BeanUtil.copyProperties(factoryFuelAttributes, FuelAttributeVo.class);
//            attributesMap = attributes.stream().collect(Collectors.groupingBy(FuelAttributeVo::getFuelId));
//        }
//        Map<Long, List<FuelAttributeVo>> finalAttributesMap = attributesMap;
//        fuelPoundDetailVos.forEach(f->{
//            List<FuelAttributeVo> attributeVos = finalAttributesMap.get(f.getFuelId());
//            f.setAttributeList(attributeVos);
//        });
        return fuelPoundDetailVos;
    }

    /**
     * 新增磅单信息
     *
     * @param fuelPound 磅单信息
     * @return 结果
     */
    @Override
    public int insertFuelPound(FuelPound fuelPound)
    {
        fuelPound.setCreateTime(DateUtils.getNowDate());
        return fuelPoundMapper.insertFuelPound(fuelPound);
    }

    /**
     * 修改磅单信息
     *
     * @param fuelPound 磅单信息
     * @return 结果
     */
    @Override
    public int updateFuelPound(FuelPound fuelPound)
    {
        return fuelPoundMapper.updateFuelPound(fuelPound);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateFuelPoundData(FuelPoundUpdate fuelPound) {
        FuelPound fuelPound1 = fuelPoundMapper.selectFuelPoundById(fuelPound.getId());
        Integer state = fuelPound1.getState();
        //过磅
        if(PoundState.STATE_1.equals(fuelPound.getState())){
            String poundPic = fuelPound.getPoundPic();
            if(StringUtils.isNotBlank(poundPic)){
                String[] split = poundPic.split(",");
                JsonUtils.obj2Json(split);
                fuelPound.setPoundPic(JsonUtils.obj2Json(split));
            }
        }
        //回皮
        if(PoundState.STATE_3.equals(fuelPound.getState())){
            Double grossWeight = fuelPound1.getGrossWeight();
            Double tareWeight = fuelPound.getTareWeight();
            boolean compare = Arith.compare(tareWeight, grossWeight);
            if(compare){
                throw new ServiceException("数据异常,皮重不能大于毛重");
            }
            double sub = Arith.sub(grossWeight, tareWeight);
            fuelPound.setNetWeight(sub);
            String poundPic = fuelPound.getPoundPic();
            if(StringUtils.isNotBlank(poundPic)){
                String[] split = poundPic.split(",");
                JsonUtils.obj2Json(split);
                fuelPound.setPoundPic(JsonUtils.obj2Json(split));
            }
        }
        if(PoundState.STATE_4.equals(fuelPound.getState())){
            String qualityPic = fuelPound.getQualityPic();
            if(StringUtils.isNotBlank(qualityPic)){
                String[] split = qualityPic.split(",");
                JsonUtils.obj2Json(split);
                fuelPound.setQualityPic(JsonUtils.obj2Json(split));
            }
        }
        //化验
        if(PoundState.STATE_5.equals(fuelPound.getState())){
            List<FuelAssayResultVo> attributeList = fuelPound.getAttributeList();
            fuelPound.setAssayResult(JsonUtils.obj2Json(attributeList));
            fuelPound.setState(PoundState.STATE_5);
            int r = fuelPoundMapper.updateFuelPound(fuelPound);
            List<FuelPoundAssay> assayList = assembleFuelPoundAssay(attributeList, fuelPound.getId());
            fuelPoundAssayMapper.batchInsertFuelPoundAssay(assayList);
            PoundSettleEvent event = new PoundSettleEvent(this,fuelPound.getId());
            eventPublisher.publishEvent(event);
            return r;
        }
        return fuelPoundMapper.updateFuelPound(fuelPound);
    }

    private List<FuelPoundAssay> assembleFuelPoundAssay(List<FuelAssayResultVo> attributeList,Long poundId){
        List<FuelPoundAssay> assayList = new ArrayList<>();
        attributeList.forEach(a->{
            FuelPoundAssay fuelPoundAssay = new FuelPoundAssay();
            fuelPoundAssay.setPoundId(poundId);
            fuelPoundAssay.setAttrId(a.getId());
            fuelPoundAssay.setAttrName(a.getAttrName());
            fuelPoundAssay.setAttrValue(a.getValue());
            assayList.add(fuelPoundAssay);
        });
        return assayList;
    }

    /**
     * 批量删除磅单信息
     *
     * @param ids 需要删除的磅单信息主键
     * @return 结果
     */
    @Override
    public int deleteFuelPoundByIds(Long[] ids)
    {
        return fuelPoundMapper.deleteFuelPoundByIds(ids);
    }

    /**
     * 删除磅单信息信息
     *
     * @param id 磅单信息主键
     * @return 结果
     */
    @Override
    public int deleteFuelPoundById(Long id)
    {
        return fuelPoundMapper.deleteFuelPoundById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assayResult(FuelPound fuelPound) {
        List<FuelAssayResultVo> assayResultList = JsonUtils.array2List(fuelPound.getAssayResult(), FuelAssayResultVo.class);
        if(CollectionUtils.isEmpty(assayResultList)){
            throw new ServiceException("化验结果不能为空");
        }
        List<FuelPoundAssay> assayList = assembleFuelPoundAssay(assayResultList, fuelPound.getId());
        fuelPoundMapper.updateFuelPound(fuelPound);
        fuelPoundAssayMapper.batchInsertFuelPoundAssay(assayList);
        PoundSettleEvent event = new PoundSettleEvent(this,fuelPound.getId());
        eventPublisher.publishEvent(event);
    }

    @Override
    public void backSkin(FuelPound fuelPound) {
        FuelPound fuelPoundDb = fuelPoundMapper.selectFuelPoundById(fuelPound.getId());
        if(fuelPoundDb == null){
            throw new ServiceException("磅单信息不存在");
        }
        Double grossWeight = fuelPoundDb.getGrossWeight();
        Double tareWeight = fuelPound.getTareWeight();
        boolean compare = Arith.compare(tareWeight, grossWeight);
        if(compare){
            throw new ServiceException("数据异常,皮重不能大于毛重");
        }
        double sub = Arith.sub(grossWeight, tareWeight);
        fuelPound.setNetWeight(sub);
        fuelPoundMapper.updateFuelPound(fuelPound);
    }

    @Override
    public void uploadQuality(FuelPound fuelPound) {
        FuelPound fuelPound1 = fuelPoundMapper.selectFuelPoundById(fuelPound.getId());
        Double netWeight = fuelPound1.getNetWeight();
        if(netWeight == null){
            throw new ServiceException("数据异常，净重不能为空");
        }
        boolean compare = Arith.compare(fuelPound.getDeductWeight(), netWeight);
        if(compare){
            throw new ServiceException("当前净重为："+netWeight+" 扣杂不能大于净重");
        }
        fuelPoundMapper.updateFuelPound(fuelPound);
    }
    private void calc(List<FuelDiaryVo> list){
        if(CollectionUtils.isEmpty(list)){
            return;
        }
        list.forEach(f->{
            Double deductWeight = f.getDeductWeight();
            Double netWeight = f.getNetWeight();
            double div = Arith.div(deductWeight, netWeight, 4);
            double mul = Arith.mul(div, 100);
            f.setDeductWeightRate(String.valueOf(mul));
        });
    }
    private void setParams(FuelPoundParams fuelPoundParams){
        Long supplierId = fuelPoundParams.getSupplierId();
        List<Long> supplierIds = new ArrayList<>();
        if(supplierId != null){
            SupplierInfo query = new SupplierInfo();
            query.setParentId(supplierId);
            List<SupplierInfo> supplierInfos = supplierInfoMapper.selectSupplierInfoList(query);
            if(CollectionUtils.isNotEmpty(supplierInfos)){
                List<Long> ids = supplierInfos.stream().map(SupplierInfo::getId).collect(Collectors.toList());
                supplierIds.addAll(ids);
            }
            supplierIds.add(supplierId);
            fuelPoundParams.setSupplierIds(supplierIds);
        }
    }
    @Override
    public PageInfo<FuelDiaryVo> selectFuelPoundByDate(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        setParams(fuelPoundParams);
        PageHelper.startPage(fuelPoundParams.getPageNum(),fuelPoundParams.getPageSize());
        List<FuelDiaryVo> list = fuelPoundMapper.selectFuelPoundByDate(fuelPoundParams);
        calc(list);
        PageInfo<FuelDiaryVo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<FuelDiaryVo> selectFuelPoundByFuel(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        setParams(fuelPoundParams);
        PageHelper.startPage(fuelPoundParams.getPageNum(),fuelPoundParams.getPageSize());
        List<FuelDiaryVo> list = fuelPoundMapper.selectFuelPoundByFuel(fuelPoundParams);
        calc(list);
        PageInfo<FuelDiaryVo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<FuelDiaryVo> selectFuelPoundByCar(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        setParams(fuelPoundParams);
        PageHelper.startPage(fuelPoundParams.getPageNum(),fuelPoundParams.getPageSize());
        List<FuelDiaryVo> list = fuelPoundMapper.selectFuelPoundByCar(fuelPoundParams);
        calc(list);
        PageInfo<FuelDiaryVo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<FuelDiaryVo> selectFuelPoundBySupplier(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        setParams(fuelPoundParams);
        PageHelper.startPage(fuelPoundParams.getPageNum(),fuelPoundParams.getPageSize());
        List<FuelDiaryVo> list = fuelPoundMapper.selectFuelPoundBySupplier(fuelPoundParams);

        calc(list);
        PageInfo<FuelDiaryVo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public List<FuelDiaryVo> selectFuelPoundByReservationDate(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        return fuelPoundMapper.selectFuelPoundByDate(fuelPoundParams);
    }

    @Override
    public List<FuelDiaryVo> selectFuelPoundByFuelId(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        return fuelPoundMapper.selectFuelPoundByFuel(fuelPoundParams);
    }

    @Override
    public List<FuelDiaryVo> selectFuelPoundByCarNum(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        return fuelPoundMapper.selectFuelPoundByCar(fuelPoundParams);
    }

    @Override
    public List<FuelDiaryVo> selectFuelPoundBySupplierId(FuelPoundParams fuelPoundParams) {
        //fuelPoundParams.setState(PoundState.STATE_6);
        return fuelPoundMapper.selectFuelPoundBySupplier(fuelPoundParams);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importAssay(List<FuelPoundImportParams> list) {
        if (CollectionUtils.isEmpty(list)){
            throw new ServiceException("导入数据不能为空！");
        }
        List<FuelPoundImportExtendParams> updateList = new ArrayList<>();
        String notExistTip = "<br/>{0},{1},送达日期：{2},{3},的磅单不存在";
        String stateErrorTip = "<br/>{0},{1},送达日期：{2},{3},的磅单状态为非待化验";
        String successTip = "<br/>{0},{1},送达日期：{2},{3},的磅单导入成功";
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (FuelPoundImportParams data:list) {
            String fuelName = data.getFuelName();
            String supplierName = data.getSupplierName();
            String carNum = data.getCarNum();
            String reservationDate = DateUtils.dateTime(data.getReservationDate());
            FuelPound fuelPound = fuelPoundMapper.selectFuelPoundInfo(reservationDate,supplierName,carNum);
            if(fuelPound == null){
                failureNum++;
                String msg = MessageFormat.format(notExistTip, supplierName, carNum, reservationDate, fuelName);
                failureMsg.append(msg);
            }else{
                Integer state = fuelPound.getState();
                if(!PoundState.STATE_4.equals(state)){
                    failureNum++;
                    String msg = MessageFormat.format(stateErrorTip, supplierName, carNum, reservationDate, fuelName);
                    failureMsg.append(msg);
                }else{
                    FuelPoundImportExtendParams fuelPoundImportExtendParams = BeanUtil.copyProperties(data, FuelPoundImportExtendParams.class);
                    fuelPoundImportExtendParams.setFuelId(fuelPound.getFuelId());
                    fuelPoundImportExtendParams.setId(fuelPound.getId());
                    updateList.add(fuelPoundImportExtendParams);

                    successNum++;
                    String msg = MessageFormat.format(successTip, supplierName, carNum, reservationDate, fuelName);
                    successMsg.append(msg);
                }
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        }else{
            List<FuelPoundAssay> assayList = new ArrayList<>();
            List<FuelPound> fuelPounds = assembleImportData(updateList,assayList);
            fuelPoundMapper.batchUpdateFuelPound(fuelPounds);
            int i = fuelPoundAssayMapper.batchInsertFuelPoundAssay(assayList);
            List<Long> ids = fuelPounds.stream().map(FuelPound::getId).collect(Collectors.toList());
            PoundSettleBatchEvent event = new PoundSettleBatchEvent(this,ids);
            eventPublisher.publishEvent(event);
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public FuelPoundSettleVo selectFuelSettleInfo(FuelPoundSettleParams query) {
        return fuelPoundMapper.selectFuelSettleInfo(query);
    }

    private List<FuelPound> assembleImportData(List<FuelPoundImportExtendParams> updateList,List<FuelPoundAssay> assayList){
        List<FuelPound> list = new ArrayList<>();
        if(CollectionUtils.isEmpty(updateList)){
            throw new ServiceException("本次导入失败");
        }
        List<Long> fuelIds = updateList.stream().map(FuelPoundImportExtendParams::getFuelId).collect(Collectors.toList());
        List<FactoryFuelAttribute> factoryFuelAttributes = factoryFuelAttributeMapper.selectFactoryFuelAttributeByFuelIds(fuelIds);
        if(CollectionUtils.isEmpty(factoryFuelAttributes)){
            throw new ServiceException("燃料属性配置缺失，本次导入失败");
        }
        Map<Long, List<FactoryFuelAttribute>> fuelIdGroup = factoryFuelAttributes.stream().collect(Collectors.groupingBy(FactoryFuelAttribute::getFuelId));
        for (int i = 0; i < updateList.size(); i++) {
            FuelPoundImportExtendParams u = updateList.get(i);
            Long id = u.getId();
            List<FactoryFuelAttribute> attributes = fuelIdGroup.get(u.getFuelId());
            if(CollectionUtils.isEmpty(attributes)){
                throw new ServiceException("燃料属性配置缺失，本次导入失败");
            }
            Map<String, FactoryFuelAttribute> attributeMap = attributes.stream().collect(Collectors.toMap(FactoryFuelAttribute::getAttrName, n -> n));
            List<FuelAssayResultVo> properties = u.getProperties();
            for (int j = 0; j < properties.size(); j++) {
                FuelAssayResultVo p = properties.get(j);
                String attrName = p.getAttrName();
                FactoryFuelAttribute fuelAttribute = attributeMap.get(attrName);
                if(fuelAttribute == null){
                    throw new ServiceException("燃料属性配置缺失，本次导入失败");
                }
                p.setId(fuelAttribute.getId());
                p.setFuelId(fuelAttribute.getFuelId());
            }
            setAssay(assayList,properties,id);
            FuelPound updateItem = new FuelPound();
            updateItem.setAssayResult(JsonUtils.obj2Json(properties));
            updateItem.setState(PoundState.STATE_5);
            updateItem.setId(id);
            list.add(updateItem);
        }

        return list;
    }

    private void setAssay(List<FuelPoundAssay> assayList,List<FuelAssayResultVo> properties,Long poundId){
        properties.forEach(p->{
            FuelPoundAssay assay = new FuelPoundAssay();
            assay.setAttrId(p.getId());
            assay.setAttrName(p.getAttrName());
            assay.setAttrValue(p.getValue());
            assay.setPoundId(poundId);
            assayList.add(assay);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSettleInfo(Long id) {
        FuelPound fuelPound = fuelPoundMapper.selectFuelPoundById(id);
        List<Long> fuelIds = new ArrayList<>();
        fuelIds.add(fuelPound.getFuelId());
        List<FactoryFuelAttribute> attributes = factoryFuelAttributeMapper.selectFactoryFuelAttributeByFuelIds(fuelIds);
        if(fuelPound == null){
            logger.error("磅单不存在：{}",id);
            return;
        }
        Integer state = fuelPound.getState();
        if(!PoundState.STATE_5.equals(state)){
            logger.error("磅单不是已化验待结算的状态");
            return;
        }
        //化验结果
        String assayResult = fuelPound.getAssayResult();
        if(StringUtils.isBlank(assayResult)){
            logger.error("数据异常，未获取到化验数据");
            return;
        }
        FactoryFuel factoryFuel = factoryFuelMapper.selectFactoryFuelById(fuelPound.getFuelId());
        //结算规则，根据化验结果计算结算信息
        String calcRules = fuelPound.getCalcRules();
        //如果没有结算规则，则以约定的基准价格作为结算信息
        if(StringUtils.isBlank(calcRules)){
            logger.info("磅单id={},本次没有设置结算规则，以基准价格作为结算",id);
            BigDecimal unitPrice = factoryFuel.getPrice();
            Double settleWeight = getDeductWeight(fuelPound);
            BigDecimal settlementTotalPrice = getSettlementTotalPrice(settleWeight, unitPrice);

            FuelPound update = new FuelPound();
            update.setId(id);
            update.setState(PoundState.STATE_6);
            update.setSettlementTime(new Date());
            update.setSettlementTotalPrice(settlementTotalPrice);
            update.setSettlementUnitPrice(unitPrice);
            update.setSettlementWeight(settleWeight);
            fuelPoundMapper.updateFuelPound(update);
            return;
        }
        if(StringUtils.isNotBlank(calcRules)){
            //化验结果
            List<FuelAttributeVo> assayResultList = JsonUtils.array2List(assayResult, FuelAttributeVo.class);
            if(CollectionUtils.isEmpty(assayResultList)){
                logger.error("磅单id={},化验结果为空",id);
                return;
            }
            //燃料品名属性结算规则
            List<FactoryFuelRuleSaveVo> factoryFuelRules = JsonUtils.array2List(calcRules, FactoryFuelRuleSaveVo.class);
            //得到扣杂后重量
            Double deductWeight = getDeductWeight(fuelPound);
            //得到燃料属性化验结果不在合同约定范围内的属性化验结果
            List<FuelAttributeVo> notRequireResult = getNotRequireResult(assayResultList, attributes);
            //不在要求范围内的燃料属性化验结果和结算规则进行匹配，得到结算规则
            List<FactoryFuelRuleSaveVo> assayMatchRules = assayMatchRules(notRequireResult, factoryFuelRules);
            //得到扣减重量的规则
            List<FactoryFuelRuleSaveVo> weightRules = assayMatchRules.stream().filter(a -> a.getDeductMethod() == 2).collect(Collectors.toList());
            //结算重量 = 扣杂后的重量 - 计算得到扣除的重量
            Double settleWeight = getWeight(notRequireResult, weightRules, deductWeight,id);
            //得到扣减单价的规则
            List<FactoryFuelRuleSaveVo> priceRules = assayMatchRules.stream().filter(a -> a.getDeductMethod() == 1).collect(Collectors.toList());
            BigDecimal unitPrice = fuelPound.getFuelContractPrice();
            //得到扣减后的单价
            BigDecimal price = getPrice(notRequireResult, priceRules, unitPrice, deductWeight,id);
            //计算得到结算总价格
            BigDecimal settlementTotalPrice = getSettlementTotalPrice(price,settleWeight);
            FuelPound update = new FuelPound();
            update.setId(id);
            update.setState(PoundState.STATE_6);
            update.setSettlementTime(new Date());
            update.setSettlementTotalPrice(settlementTotalPrice);
            update.setSettlementUnitPrice(price);
            update.setSettlementWeight(settleWeight);
            fuelPoundMapper.updateFuelPound(update);

            List<FuelPoundIncentive> incentives = getIncentive(assayMatchRules,id);
            if(CollectionUtils.isNotEmpty(incentives)){
                int i = fuelPoundIncentiveMapper.batchInsertFuelPoundIncentive(incentives);
            }
        }
    }

    private List<FuelPoundIncentive> getIncentive(List<FactoryFuelRuleSaveVo> assayMatchRules,Long poundId){
        List<FuelPoundIncentive> incentives = new ArrayList<>();
        if(CollectionUtils.isEmpty(assayMatchRules)){
            return incentives;
        }
        assayMatchRules.forEach(r->{
            FuelPoundIncentive fuelPoundIncentive = BeanUtil.copyProperties(r,FuelPoundIncentive.class);
            fuelPoundIncentive.setId(null);
            fuelPoundIncentive.setPoundId(poundId);
            fuelPoundIncentive.setRuleId(r.getId());
            fuelPoundIncentive.setRewardsPenaltiesRate(r.getRewardsPenaltiesPrice());
            incentives.add(fuelPoundIncentive);
        });
        return incentives;
    }

    /**
     * 合同单价 - 扣减的单价 = 结算的单价
     * @param notRequireResult 化验结果（不符合要求的化验结果）
     * @param priceRules 单价规则
     * @param unitPrice 合同单价
     * @param deductWeight 扣杂重量
     * @param id 磅单id
     */
    private BigDecimal getPrice(List<FuelAttributeVo> notRequireResult,List<FactoryFuelRuleSaveVo> priceRules,BigDecimal unitPrice,Double deductWeight,Long id){
        if(CollectionUtils.isEmpty(priceRules)){
            logger.info("扣减价格的规则为空,磅单id={}",id);
            return unitPrice;
        }
        Map<Long, FuelAttributeVo> assayMap = notRequireResult.stream().collect(Collectors.toMap(FuelAttributeVo::getId, f -> f));
        BigDecimal calcPrice = new BigDecimal(0);
        for (FactoryFuelRuleSaveVo w : priceRules) {
            //计量单位1.基于燃料重量，2.基于属性检测值
            Integer meteringUnit = w.getMeteringUnit();
            BigDecimal rewardsPenaltiesPrice = w.getRewardsPenaltiesPrice();
            double rate = (double) rewardsPenaltiesPrice.intValue();
            //奖惩计量单位：基于燃料重量
            if(meteringUnit == 1){
                calcPrice = calcPrice.add(rewardsPenaltiesPrice);
            }
            //奖惩计量单位：基于属性检测值
            if(meteringUnit == 2){
                FuelAttributeVo fuelAttributeVo = assayMap.get(w.getAttributeId());
                double value = Double.parseDouble(fuelAttributeVo.getValue());
                //扣除的总价格
                double mul = Arith.mul(rate, value);
                //单位重量的单价
                double price = Arith.div(mul, deductWeight);

                calcPrice = calcPrice.add(new BigDecimal(price));
            }

        }
        //合同价格 - 扣减的单价
        double sub = Arith.sub(unitPrice.intValue(), calcPrice.intValue());
        logger.info("扣减的价格：{},扣减后的价格：{}",calcPrice,sub);
        return new BigDecimal(sub);
    }

    /**
     * 根据规则计算得到扣减的重量（结算重量）
     * @param weightRules   按扣减重量的计价规则
     */
    private Double getWeight(List<FuelAttributeVo> notRequireResult,List<FactoryFuelRuleSaveVo> weightRules,Double deductWeight,Long id){
        if(CollectionUtils.isEmpty(weightRules)){
            logger.info("扣减重量的规则为空,磅单id={}",id);
            return deductWeight;
        }
        BigDecimal calcWeight = new BigDecimal(0);
        Map<Long, FuelAttributeVo> assayMap = notRequireResult.stream().collect(Collectors.toMap(FuelAttributeVo::getId, f -> f));
        for (FactoryFuelRuleSaveVo w : weightRules) {
            Integer meteringUnit = w.getMeteringUnit();
            BigDecimal rewardsPenaltiesPrice = w.getRewardsPenaltiesPrice();
            double rate = (double) rewardsPenaltiesPrice.intValue();
            //按燃料重量
            if (meteringUnit == 1) {
                double mul = Arith.mul(rate, deductWeight);
                calcWeight = calcWeight.add(new BigDecimal(mul));
            }
            //按检查的燃料属性值
            if (meteringUnit == 2) {
                FuelAttributeVo fuelAttributeVo = assayMap.get(w.getAttributeId());
                double value = Double.parseDouble(fuelAttributeVo.getValue());
                double mul = Arith.mul(rate, value);
                calcWeight = calcWeight.add(new BigDecimal(mul));
            }
        }
        return (double) calcWeight.intValue();
    }

    /**
     * 得到化验结果不在要求范围内的化验结果
     * @param assayResultList 化验结果
     * @return
     */
    private List<FuelAttributeVo> getNotRequireResult(List<FuelAttributeVo> assayResultList,List<FactoryFuelAttribute> attributes){
        List<FuelAttributeVo> results = new ArrayList<>();
        // 定义一个小的误差范围
        double epsilon = 1e-10;
        Map<Long, FactoryFuelAttribute> attributeMap = attributes.stream().collect(Collectors.toMap(FactoryFuelAttribute::getId, f -> f));
        Map<Long, FuelAttributeVo> assayAttributeMap = assayResultList.stream().collect(Collectors.toMap(FuelAttributeVo::getId, f -> f));
        assayAttributeMap.forEach((attrId,attribute)->{
            Double value = Double.valueOf(attribute.getValue());
            FactoryFuelAttribute fuelAttribute = attributeMap.get(attrId);
            Integer category = fuelAttribute.getCategory();

            //区间值匹配
            if(category == 1){
                Double qualityStart = Double.valueOf(fuelAttribute.getQualityStart());
                Double qualityEnd = Double.valueOf(fuelAttribute.getQualityEnd());
                //在区间内取反
                if (!((value - qualityStart) >= -epsilon && (value - qualityEnd) <= epsilon)){
                    results.add(attribute);
                }
            }
            //大于等于匹配
            if(category == 2){
                Double qualityValue = Double.valueOf(fuelAttribute.getQualityValue());
                if(!(value - qualityValue >= epsilon)){
                    results.add(attribute);
                }
            }
            //小于等于匹配
            if(category == 3){
                Double qualityValue = Double.valueOf(fuelAttribute.getQualityValue());
                if(!(value - qualityValue <= epsilon)){
                    results.add(attribute);
                }
            }
        });
        return results;
    }

    /**
     * 化验结果匹配规则
     * @param assayResultList
     * @param factoryFuelRules
     * @return
     */
    private List<FactoryFuelRuleSaveVo> assayMatchRules(List<FuelAttributeVo> assayResultList,List<FactoryFuelRuleSaveVo> factoryFuelRules){
        if(CollectionUtils.isEmpty(assayResultList)){
            logger.info("没有不在合同约定范围内的结果");
            return new ArrayList<>();
        }
        List<FactoryFuelRuleSaveVo> rules = new ArrayList<>();
        //化验结果map,key为属性id
        Map<Long, FuelAttributeVo> assayMap = assayResultList.stream().collect(Collectors.toMap(FuelAttributeVo::getId, f -> f));
        //燃料结算规则，key为属性id
        Map<Long, List<FactoryFuelRuleSaveVo>> ruleMap = factoryFuelRules.stream().collect(Collectors.groupingBy(FactoryFuelRuleSaveVo::getAttributeId));
        //通过化验结果匹配结算的规则
        assayMap.forEach((attributeId,attributeVo)->{
            List<FactoryFuelRuleSaveVo> attrRules = ruleMap.get(attributeId);
            if(CollectionUtils.isEmpty(attrRules)){
                logger.error("化验属性id={},未匹配到结算规则",attributeId);
                return;
            }
            //得到匹配的结算规则
            List<FactoryFuelRuleSaveVo> matchRule = matchRule(attributeVo, attrRules);
            if(CollectionUtils.isNotEmpty(matchRule)){
                rules.addAll(matchRule);
            }
        });
        if(CollectionUtils.isEmpty(rules)){
            logger.error("本次磅单未匹配到结算规则，请检查结算规则数据是否正确");
            return new ArrayList<>();
        }
        if(CollectionUtils.isNotEmpty(rules)){
            logger.info("匹配到的结算规则:{}",JsonUtils.obj2Json(rules));
        }
        return rules;
    }


    /**
     * 属性化验结果匹配结算规则
     * @param assayAttribute
     * @param attrRules
     * @return
     */
    private List<FactoryFuelRuleSaveVo> matchRule(FuelAttributeVo assayAttribute,List<FactoryFuelRuleSaveVo> attrRules){
        // 定义一个小的误差范围
        double epsilon = 1e-10;
        double value = Double.parseDouble(assayAttribute.getValue());
        List<FactoryFuelRuleSaveVo> rules = new ArrayList<>();
        for (FactoryFuelRuleSaveVo ruleItem : attrRules) {
            double ruleStartValue = Double.parseDouble(ruleItem.getRuleStartValue());
            double ruleEndValue = Double.parseDouble(ruleItem.getRuleEndValue());
            //左闭，右开
            if ((value - ruleStartValue) >= -epsilon && (value < ruleEndValue)) {
                rules.add(ruleItem);
            }
        }
        if(CollectionUtils.isEmpty(rules)){
            logger.error("属性id={},未匹配到计算规则",assayAttribute.getId());
        }
        return rules;
    }

    /**
     * 计算得到结算总价格
     * @param unitPrice
     * @param settleWeight
     * @return
     */
    private BigDecimal getSettlementTotalPrice(BigDecimal unitPrice,Double settleWeight){
        double price = Arith.mul((double) unitPrice.intValue(), settleWeight);
        return new BigDecimal(price);
    }


    /**
     * 获取扣杂后的重量 = 净重 - 扣杂
     * @param fuelPound
     * @return
     */
    private Double getDeductWeight(FuelPound fuelPound){
        Double netWeight = fuelPound.getNetWeight();
        Double deductWeight = fuelPound.getDeductWeight();
        if(deductWeight == null){
            deductWeight = 0d;
        }
        if(netWeight == null){
            logger.error("数据异常，净重数据为空：{}",fuelPound.getId());
            return 0d;
        }
        return Arith.sub(netWeight, deductWeight);
    }

    /**
     * 获取结算的金额
     * @param settleWeight
     * @param unitPrice
     * @return
     */
    private BigDecimal getSettlementTotalPrice(Double settleWeight,BigDecimal unitPrice){
        double mul = Arith.mul(settleWeight, (double) unitPrice.intValue());
        return new BigDecimal(mul);
    }
}
